package com.party.mobile.biz.analysis;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.party.common.paging.Page;
import com.party.common.utils.DateUtils;
import com.party.common.utils.HttpServletRequestUtils;
import com.party.common.utils.PartyCode;
import com.party.common.utils.StringUtils;
import com.party.core.exception.BusinessException;
import com.party.core.model.analysis.*;
import com.party.core.model.member.MemberGroup;
import com.party.core.service.analysis.*;
import com.party.core.service.member.IMemberGroupService;
import com.party.core.utils.MyBeanUtils;
import com.party.mobile.web.dto.analysis.PageFlowInput;
import com.party.mobile.web.dto.analysis.PageLoadTimeInput;
import nl.bitwalker.useragentutils.UserAgent;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 流程业务处理
 *
 * @author yifeng
 * @date 2018/8/8 0008
 * @time 下午 19:48
 */
@Service
public class StatisticsFlowBizService {
    @Autowired
    private IStatisticsPageFlowService statisticsPageFlowService;
    @Autowired
    private IStatisticsFunnelFlowService statisticsFunnelFlowService;
    @Autowired
    private IStatisticsFunnelCountService statisticsFunnelCountService;
    @Autowired
    private IStatisticsEventFlowService statisticsEventFlowService;
    @Autowired
    private IStatisticsPageCountService statisticsPageCountService;
    @Autowired
    private IMemberGroupService memberGroupService;

    public final String pageRedisKey = "page_unique_code";

    public final String pageFlowRedisKey = "page_flow_id";

    public final String eventRedisKey = "event_unique_code";

    public final String userIdRedisKey = "user_unique_code";

    Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 进入页面时，保存记录
     *
     * @param flowInput 输入参数
     * @param request   request
     * @return
     */
    public String insertPageFlow(PageFlowInput flowInput, HttpServletRequest request) throws Exception {
        StatisticsPageFlow pageFlow = new StatisticsPageFlow();

        String loadTime = flowInput.getLoadTime();
        if (StringUtils.isNotEmpty(loadTime)) {
            PageLoadTimeInput loadTimeObj = JSONObject.parseObject(loadTime, PageLoadTimeInput.class);
            if (loadTimeObj != null) {
                MyBeanUtils.copyBeanNotNull2Bean(loadTimeObj, pageFlow);
            }
        }

        String htmlUrl = flowInput.getHtmlUrl();
        if (StringUtils.isNotEmpty(htmlUrl)) {
            if (htmlUrl.contains("?r=")) {
                htmlUrl = htmlUrl.substring(0, htmlUrl.indexOf("?r="));
            } else if (htmlUrl.contains("&r=")) {
                htmlUrl = htmlUrl.substring(0, htmlUrl.indexOf("&r="));
            } else if (htmlUrl.contains("&v=")) {
                htmlUrl = htmlUrl.substring(0, htmlUrl.indexOf("&v="));
            }
            htmlUrl = htmlUrl.replace("&giftFlag=true", "")
                    .replace("&qrFlag=true", "")
                    .replace("&from=groupmessage", "")
                    .replace("?from=timeline", "")
                    .replace("&from=timeline", "")
                    .replace("&isappinstalled=0", "")
                    .replace("&from=message", "")
                    .replace("&from=singlemessage", "");

            String newHtmlUrl = htmlUrl.substring(htmlUrl.length() - 1, htmlUrl.length());
            if ("?".equals(newHtmlUrl) || "&".equals(newHtmlUrl)) {
                htmlUrl = htmlUrl.substring(0, htmlUrl.length() - 1);
            }
        }
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        // 合作商
        pageFlow.setPartnerId(flowInput.getPartnerId());
        // 页面名称
        pageFlow.setName(flowInput.getName());
        // 页面路径
        pageFlow.setUrl(htmlUrl);
        // 浏览器
        pageFlow.setBrower(userAgent.getBrowser().toString());
        // 操作系统
        pageFlow.setOs(userAgent.getOperatingSystem().toString());
        // ip
        String ip = HttpServletRequestUtils.getRemoteIpAddress(request);
        pageFlow.setIp(ip);
        // 运营商
        // String operator = HttpServletRequestUtils.getAddresses(ip);
        // pageFlow.setOperator(operator);
        // 用户编号
        pageFlow.setUserId(flowInput.getUserId());
        // 分辨率
        pageFlow.setDpi(flowInput.getDpi());
        // 唯一码
        pageFlow.setUniqueCode(flowInput.getUniqueCode());
        pageFlow.setModule(flowInput.getModule());
        /**
         * lastHtmlUrl不为空，说明不是第一个页面，找到直属父级对象。
         */
//        if (StringUtils.isNotEmpty(flowInput.getParentId())) {
//            pageFlow.setIsStart(YesNoStatus.NO.getCode());
//            pageFlow.setParentId(flowInput.getParentId());
//        } else {
//            pageFlow.setIsStart(YesNoStatus.YES.getCode());
//            pageFlow.setIsEnd(YesNoStatus.NO.getCode());
//        }
        return statisticsPageFlowService.insert(pageFlow);
    }

    /**
     * 离开页面时，更新停留时长
     *
     * @param flowInput 输入参数
     */
    public void updatePageStayTime(PageFlowInput flowInput, HttpServletRequest request) {
        String flowId = getCookieByKey(request, pageFlowRedisKey);
        if (StringUtils.isEmpty(flowId)) {
            throw new BusinessException(PartyCode.PARAMETER_ILLEGAL, "流程主键为空");
        }
        if (!"-1".equals(flowId)) {
            StatisticsPageFlow pageFlow = statisticsPageFlowService.get(flowId);
            if (pageFlow != null) {
                pageFlow.setStayTime(flowInput.getStayTime());
                statisticsPageFlowService.update(pageFlow);
            }
        }
    }

    /**
     * 从cookie里面获取唯一码
     *
     * @param request
     * @return
     */
    public String getCookieByKey(HttpServletRequest request, String key) {
        String uniqueCode = null;
        Cookie[] cookies = request.getCookies();
        if (null != cookies) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(key)) {
                    uniqueCode = cookie.getValue();
                    break;
                }
            }
        }
        return uniqueCode;
    }

    /**
     * 生成唯一码
     * 把用户编号，当前页面路径，加时间戳，加随机数，md5加密，加密后的字母转成数字，倒序取18位
     *
     * @param htmlUrl 当前页面路径
     * @param userId  用户编号
     * @return
     */
    public String getUniqueCode(String htmlUrl, String userId) {
        StringBuilder sb = new StringBuilder();
        sb.append(htmlUrl);
        sb.append(userId);
        sb.append(new Random().nextInt(99999));
        sb.append(System.currentTimeMillis());
        String encodeStr = DigestUtils.md5Hex(sb.toString() + "txz123");
        List<String> strings = Lists.newArrayList();
        for (int i = 0; i < encodeStr.length(); i++) {
            char c = encodeStr.charAt(i);
            if (!Character.isDigit(c)) {
                int tempNum = (int) c;
                strings.add(tempNum + "");
            } else {
                strings.add(c + "");
            }
        }
        Collections.reverse(strings);
        String newStr = StringUtils.join(strings.toArray(), "");
        String uniqueCode = newStr.substring(0, 18);
        return uniqueCode;
    }

    /**
     * 进入页面时，更新机构id
     *
     * @param flowInput
     */
    public void updatePagePartnerId(PageFlowInput flowInput, HttpServletRequest request) {
        String flowId = getCookieByKey(request, pageFlowRedisKey);
        if (StringUtils.isEmpty(flowId)) {
            throw new BusinessException(PartyCode.PARAMETER_ILLEGAL, "流程主键为空");
        }
        if (!"-1".equals(flowId)) {
            StatisticsPageFlow pageFlow = statisticsPageFlowService.get(flowId);
            if (pageFlow != null) {
                pageFlow.setPartnerId(flowInput.getPartnerId());
                statisticsPageFlowService.update(pageFlow);
//                MemberGroup partner = memberGroupService.get(flowInput.getPartnerId());
//                if (null != partner) {
//                    pageFlow.setPartnerName(partner.getRealname());
//                }
            }
        }
    }

    /**
     * 处理漏斗转化存储到统计表
     *
     * @param funnelId  漏斗id
     * @param partnerId 机构id
     * @param date      日期
     */
    public void analysisFunnel(String funnelId, String partnerId, Date date) {
        String yesterday = DateUtils.formatDate(date);
        Map<String, Object> params = Maps.newHashMap();
        params.put("startDate", yesterday);
        params.put("endDate", yesterday);
        params.put("partnerId", partnerId);

        List<StatisticsFunnelFlow> funnelFlows = statisticsFunnelFlowService.findByFunnelId(funnelId);
        List<String> middleEvents = new LinkedList<>();
        for (StatisticsFunnelFlow funnelFlow : funnelFlows) {
            Long currentPv = 0L; // 当前Pv
            Long currentUv = 0L; // 当前Uv
            Map<String, Object> newParams = Maps.newHashMap();
            newParams.putAll(params);
            newParams.put("middleEvents", middleEvents);

            Set<String> userSet = Sets.newHashSet();
            List<StatisticsEventFlow> eventFlows = statisticsEventFlowService.findByEventId(funnelFlow.getEventId(), newParams);
            if (new Integer(1).equals(funnelFlow.getStep()) || middleEvents.size() == 1) {
                for (StatisticsEventFlow eventFlow : eventFlows) {
                    userSet.add(eventFlow.getUserId());
                }
                currentPv = Long.valueOf(eventFlows.size());
                currentUv = Long.valueOf(userSet.size());
            } else {
                for (StatisticsEventFlow eventFlow : eventFlows) {
                    String parentIds = eventFlow.getParentIds();
                    String[] split = parentIds.split(",");
                    int[] positions = new int[middleEvents.size()];
                    for (int j = 0; j < middleEvents.size(); j++) {
                        for (int i = 0; i < split.length; i++) {
                            if (middleEvents.get(j).equals(split[i])) {
                                positions[j] = i;
                                break;
                            }
                        }
                    }

                    boolean isOk = true;
                    //外层循环控制排序趟数
                    for (int i = 0; i < positions.length - 1; i++) {
                        //内层循环控制每一趟排序多少次
                        for (int j = 0; j < positions.length - 1 - i; j++) {
                            if (positions[j] > positions[j + 1]) {
                                isOk = false;
                                break;
                            }
                        }
                    }
                    if (isOk) {
                        userSet.add(eventFlow.getUserId());
                        currentUv = Long.valueOf(userSet.size());
                        currentPv++;
                    }
                    System.out.println();
                }
            }


            middleEvents.add(funnelFlow.getEventId());

            StatisticsFunnelCounter query = new StatisticsFunnelCounter();
            query.setFunnelFlowId(funnelFlow.getId());
            query.setPartnerId(partnerId);
            query.setCreateDate(date);

            StatisticsFunnelCounter funnelOutput = statisticsFunnelCountService.getUnique(query);
            if (funnelOutput == null) {
                funnelOutput = new StatisticsFunnelCounter();
            }
            funnelOutput.setUserNum(currentUv.intValue());
            funnelOutput.setEventNum(currentPv.intValue());
            funnelOutput.setFunnelFlowId(funnelFlow.getId());
            funnelOutput.setFunnelId(funnelId);
            funnelOutput.setPartnerId(partnerId);
            funnelOutput.setCreateDate(date);
            funnelOutput.setUpdateDate(date);
            if (StringUtils.isEmpty(funnelOutput.getId())) {
                statisticsFunnelCountService.insert(funnelOutput);
            } else {
                statisticsFunnelCountService.update(funnelOutput);
            }
        }
    }

    /**
     * @Description:定时任务维护页面data
     * @Param:
     * @return:
     * @Author: Huaqunhao
     * @Date: 2018/9/12/010
     */
    public void pageDataMaintenance() {

        //获取昨天的日期
        String yesterday = DateUtils.formatDate(DateUtils.yesterday());

        String startDate = yesterday + " 00:00:00";
        String endDate = yesterday + " 23:59:59";

        //获取昨天的页面总数
        int totalCount = statisticsPageFlowService.queryPageTotalNumByDate(startDate, endDate);

        Page page = new Page();
        page.setPage(1);
        page.setLimit(1000);
        page.setTotalCount(totalCount);

        for (int i = 1; i <= page.getTotalPages(); i++) {
            page.setPage(i);
            List<StatisticsPageFlow> spflist = statisticsPageFlowService.queryPageBydate(startDate, endDate, page.getOffset(), page.getLimit());
            int spflistCount = spflist.size();
            for (int j = 0; j < spflist.size(); j++) {
                StatisticsPageFlow spfObj = spflist.get(j);

                //设置机构名
                MemberGroup member = memberGroupService.get(spfObj.getPartnerId());
                if (null != member) {
                    spfObj.setPartnerName(member.getRealname());
                }
                //如果是第一个
                if (j == 0) {
                    //设置为流程起始页
                    spfObj.setIsStart(1);

                    //在当天页面列表大于1且下一个对象的UniqueCode不同的前提下，设置流程结束页
                    if (spflistCount > 2) {
                        StatisticsPageFlow spfObj_to = spflist.get(j + 1);
                        if (!spfObj_to.getUniqueCode().equals(spfObj.getUniqueCode())) {
                            spfObj.setIsEnd(1);
                        }
                    } else {
                        spfObj.setIsEnd(1);
                    }
                    statisticsPageFlowService.update(spfObj);
                }
                //如果不是第一个
                else {
                    StatisticsPageFlow spfObj2 = spflist.get(j - 1);
                    //如果前一个对象的UniqueCode和当前对象的不同
                    if (!spfObj2.getUniqueCode().equals(spfObj.getUniqueCode())) {
                        //设置当前页为开始页
                        spfObj.setIsStart(1);
                        //设置上一个当前页为结束页
                        spfObj2.setIsEnd(1);

                        if (spflistCount > j + 1) {
                            StatisticsPageFlow spfObj_to = spflist.get(j + 1);
                            if (!spfObj_to.getUniqueCode().equals(spfObj.getUniqueCode())) {
                                spfObj.setIsEnd(1);
                            }
                        } else {
                            spfObj.setIsEnd(1);
                        }
                    } else {
                        //设置ParentId
                        spfObj.setParentId(spfObj2.getId());

                        //设置ParentIds
                        if (StringUtils.isNotBlank(spfObj2.getParentIds())) {

                            spfObj.setParentIds(spfObj2.getParentIds() + "," + spfObj2.getId());

                        } else {
                            spfObj.setParentIds(spfObj2.getId());
                        }
                    }
                    statisticsPageFlowService.update(spfObj);
                    statisticsPageFlowService.update(spfObj2);
                }
            }
        }
    }

    /**
     * 处理页面结果到统计表
     *
     * @param date 日期
     */
    public void analysisPage(Date date) {
        String yesterday = DateUtils.formatDate(date);
        Map<String, Object> countParams = Maps.newHashMap();
        countParams.put("startDate", yesterday + " 00:00:00");
        countParams.put("endDate", yesterday + " 23:59:59");
        Integer totalCount = statisticsPageFlowService.analysisPageCount(countParams);

        Page page = new Page();
        page.setLimit(1000);
        page.setTotalCount(totalCount);

        Map<String, Object> params = Maps.newHashMap();
        params.put("pageSize", page.getLimit());
        for (int i = page.getPage(); i < page.getTotalPages() + 1; i++) {
            page.setPage(i);
            params.put("rowNo", page.getOffset());

            for (int j = 1; j < 5; j++) {
                params.put("startDate", yesterday + " " + (j - 1) * 6 + ":00:00");
                params.put("endDate", yesterday + " " + ((j * 6) - 1) + ":59:59");
                List<PageListOutput> statisticsPageFlows = statisticsPageFlowService.analysisPage(params);
                for (PageListOutput pageFlow : statisticsPageFlows) {
                    try {
                        StatisticsPageCounter pageCounter = new StatisticsPageCounter();
                        pageCounter.setUrl(pageFlow.getUrl());
                        pageCounter.setName(pageFlow.getName());
                        pageCounter.setPageNum(pageFlow.getPv());
                        pageCounter.setStayTime(pageFlow.getStayTime());
                        pageCounter.setUserNum(pageFlow.getUv());
                        pageCounter.setOutCount(pageFlow.getOutCount());

                        pageCounter.setModule(pageFlow.getModule());
                        pageCounter.setPartnerId(pageFlow.getPartnerId());
                        pageCounter.setPartnerName(pageFlow.getPartnerName());
                        pageCounter.setCreateDate(date);
                        pageCounter.setUpdateDate(date);
                        statisticsPageCountService.insert(pageCounter);
                    } catch (Exception e) {
                        logger.error("页面统计异常", e);
                        continue;
                    }
                }
            }
        }
    }
}
